package core.proto.vis.action.renderer;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.awt.geom.RoundRectangle2D;

import prefuse.Constants;
import prefuse.render.AbstractShapeRenderer;
import prefuse.render.ImageFactory;
import prefuse.util.ColorLib;
import prefuse.util.FontLib;
import prefuse.util.GraphicsLib;
import prefuse.util.StringLib;
import prefuse.visual.DecoratorItem;
import prefuse.visual.EdgeItem;
import prefuse.visual.NodeItem;
import prefuse.visual.VisualItem;

/**
 * Renderer that draws a label, which consists of a text string, an image, or
 * both.
 * 
 * <p>
 * When created using the default constructor, the renderer attempts to use text
 * from the "label" field. To use a different field, use the appropriate
 * constructor or use the {@link #setTextField(String)} method. To perform
 * custom String selection, subclass this Renderer and override the
 * {@link #getText(VisualItem)} method. When the text field is <code>null</code>
 * , no text label will be shown. Labels can span multiple lines of text,
 * determined by the presence of newline characters ('\n') within the text
 * string.
 * </p>
 * 
 * <p>
 * By default, no image is shown. To show an image, the image field needs to be
 * set, either using the appropriate constructor or the
 * {@link #setImageField(String)} method. The value of the image field should be
 * a text string indicating the location of the image file to use. The string
 * should be either a URL, a file located on the current classpath, or a file on
 * the local filesystem. If found, the image will be managed internally by an
 * {@link ImageFactory} instance, which maintains a cache of loaded images.
 * </p>
 * 
 * <p>
 * The position of the image relative to text can be set using the
 * {@link #setImagePosition(int)} method. Images can be placed to the left,
 * right, above, or below the text. The horizontal and vertical alignments of
 * either the text or the image can be set explicitly using the appropriate
 * methods of this class (e.g., {@link #setHorizontalTextAlignment(int)}). By
 * default, both the text and images are centered along both the horizontal and
 * vertical directions.
 * </p>
 * 
 * @author <a href="http://jheer.org">jeffrey heer</a>
 */
public class RotationLabelRenderer extends AbstractShapeRenderer
{

    protected ImageFactory m_images = null;

    protected String m_delim = "\n";

    protected String m_labelName = "label";

    protected String m_imageName = null;

    protected int m_xAlign = Constants.CENTER;

    protected int m_yAlign = Constants.CENTER;

    protected int m_hTextAlign = Constants.CENTER;

    protected int m_vTextAlign = Constants.CENTER;

    protected int m_hImageAlign = Constants.CENTER;

    protected int m_vImageAlign = Constants.CENTER;

    protected int m_imagePos = Constants.LEFT;

    protected int m_horizBorder = 2;

    protected int m_vertBorder = 0;

    protected int m_imageMargin = 2;

    protected int m_arcWidth = 0;

    protected int m_arcHeight = 0;

    protected int m_maxTextWidth = -1;

    /** Transform used to scale and position images */
    AffineTransform m_transform = new AffineTransform();

    /** The holder for the currently computed bounding box */
    protected RectangularShape m_bbox = new Rectangle2D.Double();

    protected Point2D m_pt = new Point2D.Double(); // temp point

    protected Font m_font; // temp font holder

    protected String m_text; // label text

    protected Dimension m_textDim = new Dimension(); // text width / height

    /**
     * Create a new LabelRenderer. By default the field "label" is used as the
     * field name for looking up text, and no image is used.
     */
    public RotationLabelRenderer() {
    }

    /**
     * Create a new LabelRenderer. Draws a text label using the given text data
     * field and does not draw an image.
     * 
     * @param textField
     *            the data field for the text label.
     */
    public RotationLabelRenderer( String textField ) {
        this.setTextField( textField );
    }

    /**
     * Create a new LabelRenderer. Draws a text label using the given text data
     * field, and draws the image at the location reported by the given image
     * data field.
     * 
     * @param textField
     *            the data field for the text label
     * @param imageField
     *            the data field for the image location. This value in the data
     *            field should be a URL, a file within the current classpath, a
     *            file on the filesystem, or null for no image. If the
     *            <code>imageField</code> parameter is null, no images at all
     *            will be drawn.
     */
    public RotationLabelRenderer( String textField, String imageField ) {
        setTextField( textField );
        setImageField( imageField );
    }

    // ------------------------------------------------------------------------

    /**
     * Rounds the corners of the bounding rectangle in which the text string is
     * rendered. This will only be seen if either the stroke or fill color is
     * non-transparent.
     * 
     * @param arcWidth
     *            the width of the curved corner
     * @param arcHeight
     *            the height of the curved corner
     */
    public void setRoundedCorner( int arcWidth, int arcHeight ) {
        if( (arcWidth == 0 || arcHeight == 0)
                && !(m_bbox instanceof Rectangle2D) ) {
            m_bbox = new Rectangle2D.Double();
        } else {
            if( !(m_bbox instanceof RoundRectangle2D) )
                m_bbox = new RoundRectangle2D.Double();
            ((RoundRectangle2D) m_bbox).setRoundRect( 0, 0, 10, 10, arcWidth,
                    arcHeight );
            m_arcWidth = arcWidth;
            m_arcHeight = arcHeight;
        }
    }

    /**
     * Get the field name to use for text labels.
     * 
     * @return the data field for text labels, or null for no text
     */
    public String getTextField() {
        return m_labelName;
    }

    /**
     * Set the field name to use for text labels.
     * 
     * @param textField
     *            the data field for text labels, or null for no text
     */
    public void setTextField( String textField ) {
        m_labelName = textField;
    }

    /**
     * Sets the maximum width that should be allowed of the text label. A value
     * of -1 specifies no limit (this is the default).
     * 
     * @param maxWidth
     *            the maximum width of the text or -1 for no limit
     */
    public void setMaxTextWidth( int maxWidth ) {
        m_maxTextWidth = maxWidth;
    }

    /**
     * Returns the text to draw. Subclasses can override this class to perform
     * custom text selection.
     * 
     * @param item
     *            the item to represent as a <code>String</code>
     * @return a <code>String</code> to draw
     */
    protected String getText( VisualItem item ) {
        String s = null;
        if( item.canGetString( m_labelName ) ) {
            return item.getString( m_labelName );
        }
        return s;
    }

    // ------------------------------------------------------------------------
    // Image Handling

    /**
     * Get the data field for image locations. The value stored in the data
     * field should be a URL, a file within the current classpath, a file on the
     * filesystem, or null for no image.
     * 
     * @return the data field for image locations, or null for no images
     */
    public String getImageField() {
        return m_imageName;
    }

    /**
     * Set the data field for image locations. The value stored in the data
     * field should be a URL, a file within the current classpath, a file on the
     * filesystem, or null for no image. If the <code>imageField</code>
     * parameter is null, no images at all will be drawn.
     * 
     * @param imageField
     *            the data field for image locations, or null for no images
     */
    public void setImageField( String imageField ) {
        if( imageField != null )
            m_images = new ImageFactory();
        m_imageName = imageField;
    }

    /**
     * Sets the maximum image dimensions, used to control scaling of loaded
     * images. This scaling is enforced immediately upon loading of the image.
     * 
     * @param width
     *            the maximum width of images (-1 for no limit)
     * @param height
     *            the maximum height of images (-1 for no limit)
     */
    public void setMaxImageDimensions( int width, int height ) {
        if( m_images == null )
            m_images = new ImageFactory();
        m_images.setMaxImageDimensions( width, height );
    }

    /**
     * Returns a location string for the image to draw. Subclasses can override
     * this class to perform custom image selection beyond looking up the value
     * from a data field.
     * 
     * @param item
     *            the item for which to select an image to draw
     * @return the location string for the image to use, or null for no image
     */
    protected String getImageLocation( VisualItem item ) {
        return item.canGetString( m_imageName ) ? item.getString( m_imageName )
                : null;
    }

    /**
     * Get the image to include in the label for the given VisualItem.
     * 
     * @param item
     *            the item to get an image for
     * @return the image for the item, or null for no image
     */
    protected Image getImage( VisualItem item ) {
        String imageLoc = getImageLocation( item );
        return (imageLoc == null ? null : m_images.getImage( imageLoc ));
    }

    // ------------------------------------------------------------------------
    // Rendering

    private String computeTextDimensions( VisualItem item, String text,
            double size ) {
        // put item font in temp member variable
        m_font = item.getFont();
        // scale the font as needed
        if( size != 1 ) {
            m_font = FontLib.getFont( m_font.getName(), m_font.getStyle(), size
                    * m_font.getSize() );
        }

        FontMetrics fm = DEFAULT_GRAPHICS.getFontMetrics( m_font );
        StringBuffer str = null;

        // compute the number of lines and the maximum width
        int nlines = 1, w = 0, start = 0, end = text.indexOf( m_delim );
        m_textDim.width = 0;
        String line;
        for( ; end >= 0; ++nlines ) {
            w = fm.stringWidth( line = text.substring( start, end ) );
            // abbreviate line as needed
            if( m_maxTextWidth > -1 && w > m_maxTextWidth ) {
                if( str == null )
                    str = new StringBuffer( text.substring( 0, start ) );
                str.append( StringLib.abbreviate( line, fm, m_maxTextWidth ) );
                str.append( m_delim );
                w = m_maxTextWidth;
            } else if( str != null ) {
                str.append( line ).append( m_delim );
            }
            // update maximum width and substring indices
            m_textDim.width = Math.max( m_textDim.width, w );
            start = end + 1;
            end = text.indexOf( m_delim, start );
        }
        w = fm.stringWidth( line = text.substring( start ) );
        // abbreviate line as needed
        if( m_maxTextWidth > -1 && w > m_maxTextWidth ) {
            if( str == null )
                str = new StringBuffer( text.substring( 0, start ) );
            str.append( StringLib.abbreviate( line, fm, m_maxTextWidth ) );
            w = m_maxTextWidth;
        } else if( str != null ) {
            str.append( line );
        }
        // update maximum width
        m_textDim.width = Math.max( m_textDim.width, w );

        // compute the text height
        m_textDim.height = fm.getHeight() * nlines;

        return str == null ? text : str.toString();
    }

    /**
     * @see prefuse.render.AbstractShapeRenderer#getRawShape(prefuse.visual.VisualItem)
     */
    protected Shape getRawShape( VisualItem item ) {
        m_text = getText( item );
        Image img = getImage( item );
        double size = item.getSize();

        // get image dimensions
        double iw = 0, ih = 0;
        if( img != null ) {
            ih = img.getHeight( null );
            iw = img.getWidth( null );
        }

        // get text dimensions
        int tw = 0, th = 0;
        if( m_text != null ) {
            m_text = computeTextDimensions( item, m_text, size );
            th = m_textDim.height;
            tw = m_textDim.width;
        }

        // get bounding box dimensions
        double w = 0, h = 0;
        switch (m_imagePos) {
        case Constants.LEFT:
        case Constants.RIGHT:
            w = tw
                    + size
                    * (iw + 2 * m_horizBorder + (tw > 0 && iw > 0 ? m_imageMargin
                            : 0));
            h = Math.max( th, size * ih ) + size * 2 * m_vertBorder;
            break;
        case Constants.TOP:
        case Constants.BOTTOM:
            w = Math.max( tw, size * iw ) + size * 2 * m_horizBorder;
            h = th
                    + size
                    * (ih + 2 * m_vertBorder + (th > 0 && ih > 0 ? m_imageMargin
                            : 0));
            break;
        default:
            throw new IllegalStateException(
                    "Unrecognized image alignment setting." );
        }

        // get the top-left point, using the current alignment settings
        getAlignedPoint( m_pt, item, w, h, m_xAlign, m_yAlign );

        if( m_bbox instanceof RoundRectangle2D ) {
            RoundRectangle2D rr = (RoundRectangle2D) m_bbox;
            rr.setRoundRect( m_pt.getX(), m_pt.getY(), w, h, size * m_arcWidth,
                    size * m_arcHeight );
        } else {
            m_bbox.setFrame( m_pt.getX(), m_pt.getY(), w, h );
        }
        return m_bbox;
    }

    /**
     * Helper method, which calculates the top-left co-ordinate of an item given
     * the item's alignment.
     */
    protected static void getAlignedPoint( Point2D p, VisualItem item,
            double w, double h, int xAlign, int yAlign ) {
        double x = item.getX(), y = item.getY();
        if( Double.isNaN( x ) || Double.isInfinite( x ) )
            x = 0; // safety check
        if( Double.isNaN( y ) || Double.isInfinite( y ) )
            y = 0; // safety check

        if( xAlign == Constants.CENTER ) {
            x = x - (w / 2);
        } else if( xAlign == Constants.RIGHT ) {
            x = x - w;
        }
        if( yAlign == Constants.CENTER ) {
            y = y - (h / 2);
        } else if( yAlign == Constants.BOTTOM ) {
            y = y - h;
        }
        p.setLocation( x, y );
    }

    /**
     * @see prefuse.render.Renderer#render(java.awt.Graphics2D,
     *      prefuse.visual.VisualItem)
     */
    public void render( Graphics2D g, VisualItem item ) {
        RectangularShape shape = (RectangularShape) getRawShape( item );
        if( shape == null )
            return;

        // now render the image and text
        String text = m_text;
        Image img = getImage( item );

        if( text == null && img == null )
            return;

        double size = item.getSize();
        boolean useInt = 1.5 > Math.max( g.getTransform().getScaleX(), g
                .getTransform().getScaleY() );
        double x = shape.getMinX() + size * m_horizBorder;
        double y = shape.getMinY() + size * m_vertBorder;

        // CMC rotate before drawing; rotation in degrees
        double rotation = 0;
        if( item.canGetDouble( "rotation" ) )
            rotation = item.getDouble( "rotation" );

        double tanDegrees = 0.0;
        if( item instanceof DecoratorItem ) {
            EdgeItem edgeItem = (EdgeItem) ((DecoratorItem) item)
                    .getDecoratedItem();
            NodeItem source = edgeItem.getSourceItem();
            NodeItem target = edgeItem.getTargetItem();
            double dx = target.getX() - source.getX();
            double dy = target.getY() - source.getY();

            tanDegrees = Math.toDegrees( Math.atan2( dy, dx ) );
        }

        rotation += tanDegrees;

        if( Math.abs( rotation ) > 90 ) {
            rotation += 180;
        }

        // do transform on graphics context instead of shape; allows rendering
        // as a rectangular shape (faster)
        AffineTransform oldTrans = g.getTransform();
        if( rotation != 0 )
            g.rotate( rotation * 2 * Math.PI / 360, shape.getCenterX(),
                    shape.getCenterY() );

        // fill the shape, if requested
        int type = getRenderType( item );
        if( type == RENDER_TYPE_FILL || type == RENDER_TYPE_DRAW_AND_FILL )
            GraphicsLib.paint( g, item, shape, getStroke( item ),
                    RENDER_TYPE_FILL );

        // render image
        if( img != null ) {
            double w = size * img.getWidth( null );
            double h = size * img.getHeight( null );
            double ix = x, iy = y;

            // determine one co-ordinate based on the image position
            switch (m_imagePos) {
            case Constants.LEFT:
                x += w + size * m_imageMargin;
                break;
            case Constants.RIGHT:
                ix = shape.getMaxX() - size * m_horizBorder - w;
                break;
            case Constants.TOP:
                y += h + size * m_imageMargin;
                break;
            case Constants.BOTTOM:
                iy = shape.getMaxY() - size * m_vertBorder - h;
                break;
            default:
                throw new IllegalStateException(
                        "Unrecognized image alignment setting." );
            }

            // determine the other coordinate based on image alignment
            switch (m_imagePos) {
            case Constants.LEFT:
            case Constants.RIGHT:
                // need to set image y-coordinate
                switch (m_vImageAlign) {
                case Constants.TOP:
                    break;
                case Constants.BOTTOM:
                    iy = shape.getMaxY() - size * m_vertBorder - h;
                    break;
                case Constants.CENTER:
                    iy = shape.getCenterY() - h / 2;
                    break;
                }
                break;
            case Constants.TOP:
            case Constants.BOTTOM:
                // need to set image x-coordinate
                switch (m_hImageAlign) {
                case Constants.LEFT:
                    break;
                case Constants.RIGHT:
                    ix = shape.getMaxX() - size * m_horizBorder - w;
                    break;
                case Constants.CENTER:
                    ix = shape.getCenterX() - w / 2;
                    break;
                }
                break;
            }

            if( useInt && size == 1.0 ) {
                // if possible, use integer precision
                // results in faster, flicker-free image rendering
                g.drawImage( img, (int) ix, (int) iy, null );
            } else {
                m_transform.setTransform( size, 0, 0, size, ix, iy );
                g.drawImage( img, m_transform, null );
            }
        }

        // render text
        int textColor = item.getTextColor();
        if( text != null && ColorLib.alpha( textColor ) > 0 ) {
            g.setPaint( ColorLib.getColor( textColor ) );
            g.setFont( m_font );
            FontMetrics fm = DEFAULT_GRAPHICS.getFontMetrics( m_font );

            // compute available height
            double th;
            switch (m_imagePos) {
            case Constants.LEFT:
            case Constants.RIGHT:
                th = shape.getHeight() - 2 * size * m_vertBorder;
                break;
            default:
                th = m_textDim.height;
            }

            // compute starting y-coordinate
            y += fm.getAscent();
            switch (m_vTextAlign) {
            case Constants.TOP:
                break;
            case Constants.BOTTOM:
                y += th - m_textDim.height;
                break;
            case Constants.CENTER:
                y += (th - m_textDim.height) / 2;
            }

            // render each line of text
            int lh = fm.getHeight(); // the line height
            int start = 0, end = text.indexOf( m_delim );
            for( ; end >= 0; y += lh ) {
                drawString( g, fm, text.substring( start, end ), useInt, item
                        .getBounds().getCenterX(), item.getBounds()
                        .getCenterY(), 0 );
                start = end + 1;
                end = text.indexOf( m_delim, start );
            }
            drawString( g, fm, text.substring( start ), useInt, item
                    .getBounds().getCenterX(), item.getBounds().getCenterY(), 0 );
            // drawString( g, fm, text.substring( start ), useInt, x, y, tw,
            // item
            // .getBounds().getCenterX(), item.getBounds().getCenterY(), 0 );
        }

        // draw border
        if( type == RENDER_TYPE_DRAW || type == RENDER_TYPE_DRAW_AND_FILL ) {
            GraphicsLib.paint( g, item, shape, getStroke( item ),
                    RENDER_TYPE_DRAW );
        }
        g.setTransform( oldTrans );

    }

    private final void drawString( Graphics2D g, FontMetrics fm, String text,
            boolean useInt, double x, double y, double w ) {
        // compute the x-coordinate
        double tx;
        switch (m_hTextAlign) {
        case Constants.LEFT:
            tx = x;
            break;
        case Constants.RIGHT:
            tx = x + w - fm.stringWidth( text );
            break;
        case Constants.CENTER:
            tx = x + (w - fm.stringWidth( text )) / 2;
            break;
        default:
            throw new IllegalStateException(
                    "Unrecognized text alignment setting." );
        }
        // use integer precision unless zoomed-in
        // results in more stable drawing
        if( useInt ) {
            g.drawString( text, (int) tx, (int) y );
        } else {
            g.drawString( text, (float) tx, (float) y );
        }
    }

    /**
     * Returns the image factory used by this renderer.
     * 
     * @return the image factory
     */
    public ImageFactory getImageFactory() {
        if( m_images == null )
            m_images = new ImageFactory();
        return m_images;
    }

    /**
     * Sets the image factory used by this renderer.
     * 
     * @param ifact
     *            the image factory
     */
    public void setImageFactory( ImageFactory ifact ) {
        m_images = ifact;
    }

    // ------------------------------------------------------------------------

    /**
     * Get the horizontal text alignment within the layout. One of
     * {@link prefuse.Constants#LEFT}, {@link prefuse.Constants#RIGHT}, or
     * {@link prefuse.Constants#CENTER}. The default is centered text.
     * 
     * @return the horizontal text alignment
     */
    public int getHorizontalTextAlignment() {
        return m_hTextAlign;
    }

    /**
     * Set the horizontal text alignment within the layout. One of
     * {@link prefuse.Constants#LEFT}, {@link prefuse.Constants#RIGHT}, or
     * {@link prefuse.Constants#CENTER}. The default is centered text.
     * 
     * @param halign
     *            the desired horizontal text alignment
     */
    public void setHorizontalTextAlignment( int halign ) {
        if( halign != Constants.LEFT && halign != Constants.RIGHT
                && halign != Constants.CENTER )
            throw new IllegalArgumentException(
                    "Illegal horizontal text alignment value." );
        m_hTextAlign = halign;
    }

    /**
     * Get the vertical text alignment within the layout. One of
     * {@link prefuse.Constants#TOP}, {@link prefuse.Constants#BOTTOM}, or
     * {@link prefuse.Constants#CENTER}. The default is centered text.
     * 
     * @return the vertical text alignment
     */
    public int getVerticalTextAlignment() {
        return m_vTextAlign;
    }

    /**
     * Set the vertical text alignment within the layout. One of
     * {@link prefuse.Constants#TOP}, {@link prefuse.Constants#BOTTOM}, or
     * {@link prefuse.Constants#CENTER}. The default is centered text.
     * 
     * @param valign
     *            the desired vertical text alignment
     */
    public void setVerticalTextAlignment( int valign ) {
        if( valign != Constants.TOP && valign != Constants.BOTTOM
                && valign != Constants.CENTER )
            throw new IllegalArgumentException(
                    "Illegal vertical text alignment value." );
        m_vTextAlign = valign;
    }

    /**
     * Get the horizontal image alignment within the layout. One of
     * {@link prefuse.Constants#LEFT}, {@link prefuse.Constants#RIGHT}, or
     * {@link prefuse.Constants#CENTER}. The default is a centered image.
     * 
     * @return the horizontal image alignment
     */
    public int getHorizontalImageAlignment() {
        return m_hImageAlign;
    }

    /**
     * Set the horizontal image alignment within the layout. One of
     * {@link prefuse.Constants#LEFT}, {@link prefuse.Constants#RIGHT}, or
     * {@link prefuse.Constants#CENTER}. The default is a centered image.
     * 
     * @param halign
     *            the desired horizontal image alignment
     */
    public void setHorizontalImageAlignment( int halign ) {
        if( halign != Constants.LEFT && halign != Constants.RIGHT
                && halign != Constants.CENTER )
            throw new IllegalArgumentException(
                    "Illegal horizontal text alignment value." );
        m_hImageAlign = halign;
    }

    /**
     * Get the vertical image alignment within the layout. One of
     * {@link prefuse.Constants#TOP}, {@link prefuse.Constants#BOTTOM}, or
     * {@link prefuse.Constants#CENTER}. The default is a centered image.
     * 
     * @return the vertical image alignment
     */
    public int getVerticalImageAlignment() {
        return m_vImageAlign;
    }

    /**
     * Set the vertical image alignment within the layout. One of
     * {@link prefuse.Constants#TOP}, {@link prefuse.Constants#BOTTOM}, or
     * {@link prefuse.Constants#CENTER}. The default is a centered image.
     * 
     * @param valign
     *            the desired vertical image alignment
     */
    public void setVerticalImageAlignment( int valign ) {
        if( valign != Constants.TOP && valign != Constants.BOTTOM
                && valign != Constants.CENTER )
            throw new IllegalArgumentException(
                    "Illegal vertical text alignment value." );
        m_vImageAlign = valign;
    }

    /**
     * Get the image position, determining where the image is placed with
     * respect to the text. One of {@link Constants#LEFT},
     * {@link Constants#RIGHT}, {@link Constants#TOP}, or
     * {@link Constants#BOTTOM}. The default is left.
     * 
     * @return the image position
     */
    public int getImagePosition() {
        return m_imagePos;
    }

    /**
     * Set the image position, determining where the image is placed with
     * respect to the text. One of {@link Constants#LEFT},
     * {@link Constants#RIGHT}, {@link Constants#TOP}, or
     * {@link Constants#BOTTOM}. The default is left.
     * 
     * @param pos
     *            the desired image position
     */
    public void setImagePosition( int pos ) {
        if( pos != Constants.TOP && pos != Constants.BOTTOM
                && pos != Constants.LEFT && pos != Constants.RIGHT
                && pos != Constants.CENTER )
            throw new IllegalArgumentException( "Illegal image position value." );
        m_imagePos = pos;
    }

    // ------------------------------------------------------------------------

    /**
     * Get the horizontal alignment of this node with respect to its x, y
     * coordinates.
     * 
     * @return the horizontal alignment, one of {@link prefuse.Constants#LEFT},
     *         {@link prefuse.Constants#RIGHT}, or
     *         {@link prefuse.Constants#CENTER}.
     */
    public int getHorizontalAlignment() {
        return m_xAlign;
    }

    /**
     * Get the vertical alignment of this node with respect to its x, y
     * coordinates.
     * 
     * @return the vertical alignment, one of {@link prefuse.Constants#TOP},
     *         {@link prefuse.Constants#BOTTOM}, or
     *         {@link prefuse.Constants#CENTER}.
     */
    public int getVerticalAlignment() {
        return m_yAlign;
    }

    /**
     * Set the horizontal alignment of this node with respect to its x, y
     * coordinates.
     * 
     * @param align
     *            the horizontal alignment, one of
     *            {@link prefuse.Constants#LEFT},
     *            {@link prefuse.Constants#RIGHT}, or
     *            {@link prefuse.Constants#CENTER}.
     */
    public void setHorizontalAlignment( int align ) {
        m_xAlign = align;
    }

    /**
     * Set the vertical alignment of this node with respect to its x, y
     * coordinates.
     * 
     * @param align
     *            the vertical alignment, one of {@link prefuse.Constants#TOP},
     *            {@link prefuse.Constants#BOTTOM}, or
     *            {@link prefuse.Constants#CENTER}.
     */
    public void setVerticalAlignment( int align ) {
        m_yAlign = align;
    }

    /**
     * Returns the amount of padding in pixels between the content and the
     * border of this item along the horizontal dimension.
     * 
     * @return the horizontal padding
     */
    public int getHorizontalPadding() {
        return m_horizBorder;
    }

    /**
     * Sets the amount of padding in pixels between the content and the border
     * of this item along the horizontal dimension.
     * 
     * @param xpad
     *            the horizontal padding to set
     */
    public void setHorizontalPadding( int xpad ) {
        m_horizBorder = xpad;
    }

    /**
     * Returns the amount of padding in pixels between the content and the
     * border of this item along the vertical dimension.
     * 
     * @return the vertical padding
     */
    public int getVerticalPadding() {
        return m_vertBorder;
    }

    /**
     * Sets the amount of padding in pixels between the content and the border
     * of this item along the vertical dimension.
     * 
     * @param ypad
     *            the vertical padding
     */
    public void setVerticalPadding( int ypad ) {
        m_vertBorder = ypad;
    }

    /**
     * Get the padding, in pixels, between an image and text.
     * 
     * @return the padding between an image and text
     */
    public int getImageTextPadding() {
        return m_imageMargin;
    }

    /**
     * Set the padding, in pixels, between an image and text.
     * 
     * @param pad
     *            the padding to use between an image and text
     */
    public void setImageTextPadding( int pad ) {
        m_imageMargin = pad;
    }

} // end of class LabelRenderer
